#include "ruleEngine.h"
/** \var list<string> rmatch
    \brief The matched rules stored their IDs in this list. This was mentioned in rulefunctions.c
    * Note: It's a clean hack since getting the list of matched rules in CLIPS way was too much tedious. Saves time! */
std::list<std::string> rmatch;

/** \fn void assertBSON(BSONObj,string)
    \brief Take the key-value pairs from BSONObj and assert them as facts in the CLIPS environment
    \param BSONObj b The BSONObject
    \param string head In case of nested documents we might need to add the super key before the corresponding key
    * Postcondition: The facts are now ready in the CLIPS Environment
    \return void
    */
void ruleEngine::assertBSON(mongo::BSONObj b,std::string head)
{
    using namespace std;
    using namespace mongo;
    set<string> fnames;
    set<string>::iterator i;
    /*Get key names*/
    b.getFieldNames(fnames);
    BSONObj embedded;
    int flag;

    for(i=fnames.begin();i!=fnames.end();i++)
    {
        flag=0;
        string fieldname=(*i);
        /*In case of an Embedded document add the name of the super key to the fact string*/
        /*Format of fact (assert fact-name+ fact-value*) */
        string assertString="("+head+fieldname+" ";
        char buff[10]="\0";
        /*Check for different datatypes and assert as needed*/
        switch(b[fieldname].type())
        {
            case String:
            assertString+="\""+ b[fieldname].str()+ "\"";
            flag=1;
            break;
            case NumberDouble:
            sprintf(buff,"%f",b[fieldname].numberDouble());
            assertString+=buff;
            flag=1;
            break;
            case NumberInt:
            sprintf(buff,"%d",b[fieldname].numberInt());
            assertString+=buff;
            flag=1;
            break;
            case NumberLong:
            sprintf(buff,"%lld",b[fieldname].numberLong());
            assertString+=buff;
            flag=1;
            break;
            case jstOID:
            assertString+="\"" + b[fieldname].__oid().toString() + "\"";
            flag=1;
            break;
            case Object:
            embedded=b[fieldname].Obj();
            assertBSON(embedded,fieldname+".");
            break;
        }
        /*We have some valid data type*/
        if (flag)
        {
            /*Complete the string to be asserted*/
            assertString+=")";
            char a[1024]="\0";
            strcpy(a,assertString.c_str());
            cout<<a<<endl;
            /*CLIPS function to assert a fact as a string*/
            AssertString(a);
        }
    }
}
/** \fn ruleEngine(string)
    \brief Initializes the environment by loading the rules and user-defined external functions
    \param string fname The .clp file containing the rules and functions
    \return ruleEngine object
    */
ruleEngine::ruleEngine(std::string fname)
{
    /*Set the basic environment variables. CLIPS internal function*/
    InitializeEnvironment();
    char buff[1024]="\0";
    strcpy(buff,fname.c_str());
    /*Load the rules and functions from the file. CLIPS internal function*/
    Load(buff);
}
/** \fn list<string> match(BSONObj)
    \brief Run the CLIPS engine to get a match of rules given a BSONObject
    \param BSONObj b The BSONObj to observe
    \return list<string> A list containing the IDs of matched rules
    */
std::list<std::string> ruleEngine::match(mongo::BSONObj b)
{
    /*Clear out the old facts(if any) from the environment. CLIPS internal function*/
    Reset();
    /*Clear the list where the previous matched rules(if any) are saved*/
    rmatch.clear();
    /*Assert the BSONObject as facts in the environment*/
    assertBSON(b,"");
    /*Run the CLIPS engine. CLIPS internal function*/
    Run(-1);
    /*Return the new list*/
    return rmatch;
}

